﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Collections;
using System.Net;
using System.IO;
using System.Text;
using System.Web.Security;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;

namespace oneforty_purchase
{
    public partial class _Purchase : System.Web.UI.Page
    {
        public const string DEVELOPER_KEY = "#ChangeMe#";
        public const bool SANDBOX = true;
        public static string debug = "";

        protected void Page_Load(object sender, EventArgs e)
        {
            try
            {
                if (Request.HttpMethod.ToUpper() == "POST")
                {
                    //Check max length of request -- arbitrary max.
                    if (Request.ContentLength > 0 && Request.ContentLength < 2000)
                    {
                        //Verify the SSL Cert.
                        HttpPost(oneforty_urls.apibase, "", true);

                        //Read the request body.
                        byte[] buffer = new byte[Request.ContentLength];
                        Request.InputStream.Read(buffer, 0, Request.ContentLength);
                        string body = System.Text.UTF8Encoding.UTF8.GetString(buffer);

                        //Load the purchase object.
                        OneFortyPurchase purchase = new OneFortyPurchase();
                        purchase.developer_key = DEVELOPER_KEY;
                        purchase.Load(body);

                        switch (purchase.action)
                        {
                            case OneFortyAction.fulfillment_notification:
                                //Change the action in preparation for the acknowledgment.
                                purchase.action = OneFortyAction.fulfillment_acknowledge;
                                string json = purchase.ToJsonString();
                                //DEBUG
                                debug += json + "\r\n\r\n";
                                string uri = oneforty_urls.apibase;
                                if (SANDBOX)
                                {
                                    uri = oneforty_urls.sandboxbase;
                                }
                                //Send developer_key and reference_code back to oneforty.
                                string response = HttpPost(uri + oneforty_urls.fulfillment_acknowledge, json, false);
                                purchase.Load(response);
                                
                                //TODO:  Save the purchase information to a datastore.

                                //Custom Fulfillment -- This is an example of synchronous license key generation.
                                string license_key = KeyGenerate(purchase.buyer_twitter_handle);
                                purchase.license_key = license_key;
                                purchase.action = OneFortyAction.fulfillment_complete;
                                json = purchase.ToJsonString();
                                //DEBUG
                                debug += json + "\r\n\r\n";

                                //Complete the purchase -- Send the license key back to oneforty.com
                                response = HttpPost(uri + oneforty_urls.fulfillment_complete, json, false);
                                purchase.Load(response);
                                json = purchase.ToJsonString();
                                //DEBUG
                                debug += json + "\r\n\r\n";
                                //End Custom Fulfillment

                                break;
                            case OneFortyAction.fulfillment_void:
                                //TODO:  Void the purchase.
                                //Lookup purchase record in datastore using purchase.reference_code and purchase.edition_code.
                                break;
                            default:
                                break;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                //add appropriate error handling
                debug += ex.Message + "\r\n\r\n";
            }
            finally
            {
                File.WriteAllText(Server.MapPath(".") + "/debug.txt", debug);
            }

        }

        private string KeyGenerate(string buyer_twitter_id)
        {
            string salt = "#ChangeMe#";
            return FormsAuthentication.HashPasswordForStoringInConfigFile(buyer_twitter_id + salt, "SHA1");
        }

        private string HttpPost(string uri, string parms, bool validateCert)
        {
            StreamWriter requestWriter = null;

            HttpWebRequest webRequest = WebRequest.Create(uri) as HttpWebRequest;
            webRequest.ContentType = "application/x-www-form-urlencoded";
            webRequest.Method = "POST";
            webRequest.ServicePoint.Expect100Continue = false;
            webRequest.KeepAlive = false;

            //Validate SSL Cert
            if (validateCert)
            {
                ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(ValidateRemoteCertificate);
            }
            else
            {
                ServicePointManager.ServerCertificateValidationCallback = null;
            }

            try
            {
                requestWriter = new StreamWriter(webRequest.GetRequestStream());
                requestWriter.Write(parms);
            }
            catch (WebException ex)
            {
                //add appropriate error handling
                throw ex;
            }
            finally
            {
                if (requestWriter != null)
                {
                    requestWriter.Close();
                }
            }

            try
            {
                WebResponse webResponse = webRequest.GetResponse();
                if (webResponse == null)
                { 
                    return null; 
                }
                StreamReader sr = new StreamReader(webResponse.GetResponseStream());
                return sr.ReadToEnd().Trim();
            }
            catch (WebException ex)
            {
                //add appropriate error handling
                throw ex;
            }
        }

        private static bool ValidateRemoteCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors policyErrors)
        {
            if ((policyErrors & SslPolicyErrors.RemoteCertificateChainErrors) == SslPolicyErrors.RemoteCertificateChainErrors)
            {
                return false;
            }
            else if ((policyErrors & SslPolicyErrors.RemoteCertificateNameMismatch) == SslPolicyErrors.RemoteCertificateNameMismatch)
            {
                return false;
            }
            else if ((policyErrors & SslPolicyErrors.RemoteCertificateNotAvailable) == SslPolicyErrors.RemoteCertificateNotAvailable)
            {
                return false;
            }

            return true;
        } 
    }
}